package com.scau.jansing.util;

import com.sun.org.apache.xpath.internal.operations.Bool;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * todo 把常量抽离出来
 * todo getExceptionString 与 getInterfaceString合并
 * Created by jansing on 2015/10/7.
 */
public class CommonUtils {
    private static String[] REMOVE_STRINGS = {"class ", "interface "};
    private static String REPLACE_STRING = "";
    public static String MAVEN_EXTRA_PATH = "\\main\\java";

    /**
     * 添加class文件路径到加载器中
     *
     * @param path
     * @throws NoSuchMethodException
     * @throws FileNotFoundException
     * @throws MalformedURLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void addClassPath(String path) throws NoSuchMethodException, FileNotFoundException,
            MalformedURLException, InvocationTargetException, IllegalAccessException {
        File classPath = new File(path);
        if (!classPath.exists() || classPath.isFile()) {
            throw new FileNotFoundException("文件路径错误,请输入正确根路径");
        }
        Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        method.setAccessible(true);
        //设置类加载器
        URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        //将改路径加入到类加载器中
        method.invoke(classLoader, classPath.toURI().toURL());
    }

    /**
     * 去掉多余信息
     *
     * @param obj
     * @return
     */
    public static String removeInterfaceOrClass(Object obj) {
        String temp;
        if (obj instanceof AnnotatedType) { //接口
            temp = ((AnnotatedType) obj).getType().toString().replaceAll("interface ", "");
        } else {
            temp = obj.toString();
        }
        for (String s : REMOVE_STRINGS) {
            if (temp.startsWith(s)) {
                return temp.replaceFirst(s, REPLACE_STRING);
            }
        }
        return temp;
    }

    /**
     * 排版
     * todo 加上换行
     *
     * @param count
     * @return
     */
    public static String getTab(int count) {
        StringBuilder tab = new StringBuilder();
        for (int i = 0; i < count; i++)
            tab.append("\t");
        return tab.toString();
    }

    /**
     * 为String的参数加上双引号
     * 为注解的enum变量加上类信息
     *
     * @param str   com.scau.jansing.util.MethodAtInterface$Type
     * @param value MethodAtInterface.Type
     * @return
     */
    public static String getDeclareValue(String str, String value) {
        if (str.equals(String.class.getName())) {
            return "\"" + value + "\"";
        }
        if (str.contains("$")) {
            return str.replaceAll("\\$", ".") + "." + value;
        }
        return value;
    }

    /**
     * 得到声明的 类 或 构造方法 或 方法 的注解
     *
     * @param annotation
     * @return
     * @throws ClassNotFoundException
     */
    //todo CommonUtils.getDeclareAnnotation()  抽象层次
    public static String getClassDeclareAnnotation(Annotation annotation) throws ClassNotFoundException {
        StringBuilder temp = new StringBuilder();
        //得到声明的注解信息
//        System.out.println(c);
        //@com.scau.jansing.util.ClassAtInterface(value=fff, t1=t1, num=-1)
        String annotationString = annotation.toString();

        //得到声明的注解类
        String annotationDeclare = annotationString.substring(0, annotationString.indexOf("("));
//            System.out.println(annotationDeclare);
        //@com.scau.jansing.util.ClassAtInterface

        //得到声明的属性值，因为这里可能包含注解本身的默认值，需要去掉
        Map<String, String> paramsMap = new HashMap<>();
        String annotationParams = annotationString.substring(annotationString.indexOf("(") + 1, annotationString.length() - 1);
//            System.out.println(annotationParams);
        //value=fff, t1=t1, num=-1
        String[] annotationParamsKeyValue = annotationParams.split(",");
        for (String keyValueString : annotationParamsKeyValue) {
//                System.out.println(keyValueString.trim());
            String[] temp1 = keyValueString.split("=");
            String key = temp1[0];
            String value = temp1[1];
            paramsMap.put(key.trim(), value.trim());
        }

        //得到接口类属性的默认值，与上面得到的声明值对比。去掉相同的
        Class annotationClassDefault = Class.forName(annotation.annotationType().getName());
        Method[] methods = annotationClassDefault.getDeclaredMethods();
        for (Method m : methods) {
            if (paramsMap.get(m.getName()) != null &&
                    !paramsMap.get(m.getName()).equals(m.getDefaultValue().toString())) {
                if (temp.length() != 0) {
                    temp.append(", ");
                }
                temp.append(m.getName()).append(" = ")
                        .append(CommonUtils.getDeclareValue(m.getGenericReturnType().getTypeName(), paramsMap.get(m.getName())));
            }
        }
        if (temp.length() > 0) {
            temp.insert(0, "(").append(")");
        }
        temp.insert(0, annotationDeclare);
        return temp.toString();
    }

    /**
     * 得到构造函数<br/>
     * 另一种更简单的方案是用constructor.toString()，<br/>
     * 得到public com.scau.jansing.entities.Person(java.lang.String) throws java.lang.Exception<br/>
     * 然后用','分隔符得到参数类型的数组，为他们加上参数名，再拼接回去。
     *
     * @param constructor
     * @return
     * @throws ClassNotFoundException
     */
    public static String getConstructor(Constructor constructor) throws ClassNotFoundException {
        StringBuilder temp = new StringBuilder();
        //得到注解
        Iterator<Annotation> annotationIterator = Arrays.asList(constructor.getDeclaredAnnotations()).iterator();
        while (annotationIterator.hasNext())
            temp.append(CommonUtils.getTab(1))
                    .append(CommonUtils.getClassDeclareAnnotation(annotationIterator.next())).append("\n");

        //得到构造方法
        temp.append(CommonUtils.getTab(1))
                .append(Modifier.toString(constructor.getModifiers())).append(" ")
                .append(constructor.getDeclaringClass().getSimpleName()).append("(")
                //获得参数
                .append(getParameterString(constructor.getParameterTypes())).append(")")
                //获得异常
                .append(getExceptionString(constructor.getGenericExceptionTypes())).append(" {\n")
                .append(CommonUtils.getTab(1)).append("}\n");
        return temp.toString();
    }

    /**
     * 得到方法
     * @param method
     * @return
     * @throws ClassNotFoundException
     */
    public static String getMethodString(Method method) throws ClassNotFoundException {
        //实现接口时产生的一个volatile修饰的方法(用于多线程？)，多余的
        if(Modifier.toString(method.getModifiers()).contains(Modifier.toString(Modifier.VOLATILE)))
            return "";
        StringBuilder temp = new StringBuilder();
        //得到注解

        Iterator<Annotation> annotationIterator = Arrays.asList(method.getDeclaredAnnotations()).iterator();
        while (annotationIterator.hasNext())
            temp.append(CommonUtils.getTab(1))
                    .append(CommonUtils.getClassDeclareAnnotation(annotationIterator.next())).append("\n");

        //得到方法
        temp.append(CommonUtils.getTab(1))
                .append(Modifier.toString(method.getModifiers())).append(" ")
                .append(method.getGenericReturnType().getTypeName()).append(" ")
                .append(method.getName()).append("(")
                //获得参数
                .append(CommonUtils.getParameterString(method.getParameterTypes())).append(")")
                //获得异常
                .append(CommonUtils.getExceptionString(method.getGenericExceptionTypes())).append(" {\n");
        //如果返回值类型不为void，则返回null;
        if (!method.getGenericReturnType().getTypeName().equals("void")) {
            temp.append(getTab(2)).append("return null;\n");
        }
        temp.append(CommonUtils.getTab(1)).append("}\n");

        return temp.toString();
    }

    /**
     * 得到抛出的异常信息
     *
     * @param exceptions
     * @return
     */
    public static String getExceptionString(Type[] exceptions) {
        StringBuilder temp = new StringBuilder();
        Iterator<Type> exceptionIterator = Arrays.asList(exceptions).iterator();
        if (exceptionIterator.hasNext()) {
            temp.append(" throws ").append(exceptionIterator.next().getTypeName());
        }
        while (exceptionIterator.hasNext()) {
            temp.append(", ").append(exceptionIterator.next().getTypeName());
        }
        return temp.toString();
    }

    /**
     * 得到实现的接口
     *
     * @param interfaces
     * @return
     */
    public static String getInterfaceString(AnnotatedType[] interfaces) {
        StringBuilder temp = new StringBuilder();
        Iterator<AnnotatedType> interfaceIterator = Arrays.asList(interfaces).iterator();
        if (interfaceIterator.hasNext()) {
            temp.append(CommonUtils.getTab(1)).append("implements ").append(CommonUtils.removeInterfaceOrClass(interfaceIterator.next()));
        }
        while (interfaceIterator.hasNext()) {
            temp.append(", ").append(CommonUtils.removeInterfaceOrClass(interfaceIterator.next()));
        }
        return temp.toString();
    }

    /**
     * 得到参数
     *
     * @param params
     * @return
     */
    public static String getParameterString(Class[] params) {
        StringBuilder temp = new StringBuilder();
        for (int i = 0; i < params.length; i++) {
            if (i != 0) {
                temp.append(", ");
            }
            temp.append(params[i].getName()).append(" param").append(i);
        }
        return temp.toString();
    }

}
